package com.cysyz.web.modules.base.permission.service.impl;

import com.cysyz.mylib.dao.Conds;
import com.cysyz.mylib.utils.MD5;
import com.cysyz.mylib.utils.MyCollectionUtils;
import com.cysyz.mylib.utils.MyStringUtils;
import com.cysyz.mylib.utils.scanner.PackageScanner;
import com.cysyz.mylib.utils.xsvmaker.XsvMaker;
import com.cysyz.mylib.utils.xsvmaker.impl.CollectionValueGetter;
import com.cysyz.mylib.utils.xsvmaker.impl.XsvMakerImpl;
import com.cysyz.web.modules.base.lock.service.LockService;
import com.cysyz.web.modules.base.permission.annotation.Module;
import com.cysyz.web.modules.base.permission.annotation.ModuleFunction;
import com.cysyz.web.modules.base.permission.domain.SysPrivilege;
import com.cysyz.web.modules.base.permission.domain.SysRole;
import com.cysyz.web.modules.base.permission.domain.SysSysrolePrivilege;
import com.cysyz.web.modules.base.permission.domain.SysUserRole;
import com.cysyz.web.modules.base.permission.service.PrivilegeInitTool;
import com.cysyz.web.modules.base.permission.support.ModuleFunctionType;
import com.cysyz.web.modules.base.permission.support.PrivilegeType;
import com.cysyz.web.modules.base.support.controller.SpringMVCBaseController;
import com.cysyz.web.modules.base.support.service.BaseService;
import com.cysyz.web.modules.base.user.domain.SysUser;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.*;

@Service
public class PrivilegeInitToolImpl2 extends BaseService implements PrivilegeInitTool {

    @Resource
    LockService lockService;

    @Override
    public void initAdminRole() {

        Set<SysPrivilege> allPrivilegesPersistenced = getAllPrivilegesPersistenced();
        //为配置权限的一些准备工作， 配置权限需要一个admin角色,
        SysRole sysRole = configAdminRole(allPrivilegesPersistenced);

        //为admin的用户绑定这些最新持久化的privilege
        List<Long> privilegesPersistencedKeys = new ArrayList<Long>();
        for (SysPrivilege sysPrivilege : allPrivilegesPersistenced) {
            privilegesPersistencedKeys.add(sysPrivilege.getId());
        }

        this.m2MRelationshipMapping(SysRole.class, sysRole.getId(), SysPrivilege.class, privilegesPersistencedKeys, SysSysrolePrivilege.class);
    }


    @Override
    public  void initAdminUser() {
        SysUser sysUser = new SysUser();
        sysUser.setId(Long.MAX_VALUE);
        sysUser.setLoginName("admin");
        lockService.unLock(sysUser);
        //密码为admin的MD5
        sysUser.setPassword("21232f297a57a5a743894a0e4a801fc3");

        Conds conds = new Conds();
        conds.addFilter("loginName", "admin");
        List<SysUser> list = this.list(SysUser.class, conds);
        if (list != null && !list.isEmpty()) {
            sysUser = list.get(0);
        } else {
            this.save(sysUser);
        }

        Conds roleConds = new Conds();
        roleConds.addFilter("code", "admin");
        List<SysRole> roleList = this.list(SysRole.class, roleConds);

        SysRole sysRole = roleList.get(0);
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setSysUser(sysUser);
        sysUserRole.setSysRole(sysRole);

        Conds sysUserRoleConds = new Conds();
        sysUserRoleConds.addFilter("sysUser", sysUser);
        sysUserRoleConds.addFilter("sysRole", sysRole);
        List<SysUserRole> SysUserRolelist = this.list(SysUserRole.class, sysUserRoleConds);
        if (SysUserRolelist != null && !SysUserRolelist.isEmpty()) {
        } else {
            this.save(sysUserRole);
        }
    }


    @Override
    public void initGroupGroup() {
        Conds othersGroupGrouponds = new Conds();
        othersGroupGrouponds.addFilter("name", "其他");


        SysPrivilege othersGroupGroup = new SysPrivilege();
        othersGroupGroup.setName("其他");
        othersGroupGroup.setCode("othersGroupGroup");
        othersGroupGroup.setType(PrivilegeType.PRIVILEGE_GROUP_GROUP);
        List<SysPrivilege> otherGroupGroupList = this.list(SysPrivilege.class, othersGroupGrouponds);
        if (otherGroupGroupList != null && !otherGroupGroupList.isEmpty()) {
            othersGroupGroup = otherGroupGroupList.get(0);
        } else {
            this.save(othersGroupGroup);
        }

        Conds groupConds = new Conds();
        groupConds.addFilter("type", PrivilegeType.PRIVILEGE_GROUP);
        List<SysPrivilege> groupList = this.list(SysPrivilege.class, groupConds);

        if (groupList != null) {
            for (SysPrivilege sysPrivilege : groupList) {
                if (sysPrivilege.getSysPrivilege() == null) {
                    sysPrivilege.setSysPrivilege(othersGroupGroup);
                }
            }
        }
    }

    @Override
    public void initPrivilege(String... scanPackages) {

        PackageScanner moduleScanner = new PackageScanner(scanPackages, Module.class);

        Set<Class<?>> moduleClasses = moduleScanner.scanClass();

        /**
         * 校验所有类上的@Module的code没有重复，否则报错
         */
        validateAllClassModuleCode(moduleClasses);

        /**
         * 校验没有方法重载
         */
        valiateNoOverload(moduleClasses);
        //取得所有的项目中的privilege
        Set<SysPrivilege> privilegesInProject = getAllPrivilegesInProject(moduleClasses);

        //取得所有已经持久化了的privilege
        Set<SysPrivilege> privilegesPersistenced = getAllPrivilegesPersistenced();

        //比较，如果有没有持久话的privilege，把其放入等待持久化列表
        Set<SysPrivilege> privilegesToPersistence = new HashSet<SysPrivilege>();
        for (SysPrivilege privilegeIP : privilegesInProject) {
            if (!privilegesPersistenced.contains(privilegeIP)) {
                privilegesToPersistence.add(privilegeIP);
            }
        }

        //持久化所有模块类型的权限
        for (SysPrivilege sysPrivilege : privilegesToPersistence) {
            if (sysPrivilege.getType() == PrivilegeType.PRIVILEGE_GROUP) {
                this.save(sysPrivilege);
            }
        }

        //持久化所有菜单类型的权限
        for (SysPrivilege sysPrivilege : privilegesToPersistence) {
            if (sysPrivilege.getType() == PrivilegeType.MENU) {
                //把所有准备保存的实体中的父亲权限更换为已经持久化的实体
                for (SysPrivilege privilegeP : privilegesPersistenced) {
                    if (privilegeP.equals(sysPrivilege.getSysPrivilege())) {
                        sysPrivilege.setSysPrivilege(privilegeP);
                        break;
                    }
                }
                this.save(sysPrivilege);
            }
        }

        //所有的功能从属于某一特定模块，上一步中把模块类型持久化以后，在下面把所有项目中的功能权限的父亲模块更改为已经持久化了的权限
        //同时，把所有功能权限的菜单权限更改为已经持久化的权限
        for (SysPrivilege sysPrivilegeToPersistence : privilegesToPersistence) {
            if (! (sysPrivilegeToPersistence.getType() == PrivilegeType.PRIVILEGE_GROUP)) {
                //把所有准备保存的实体中的父亲权限更换为已经持久化的实体
                for (SysPrivilege privilegeP : privilegesPersistenced) {
                    if (privilegeP.equals(sysPrivilegeToPersistence.getSysPrivilege())) {
                        sysPrivilegeToPersistence.setSysPrivilege(privilegeP);
                        break;
                    }
                }


                for (SysPrivilege privilegeTP : privilegesToPersistence) {
                    if (privilegeTP.equals(sysPrivilegeToPersistence.getMenuPrivilege())) {
                        sysPrivilegeToPersistence.setMenuPrivilege(privilegeTP);
                        break;
                    }
                }

                for (SysPrivilege privilegeP : privilegesPersistenced) {
                    if (privilegeP.equals(sysPrivilegeToPersistence.getMenuPrivilege())) {
                        sysPrivilegeToPersistence.setMenuPrivilege(privilegeP);
                        break;
                    }
                }

                this.save(sysPrivilegeToPersistence);
            }
        }
    }

    private void valiateNoOverload(Set<Class<?>> moduleClasses) {
        for (Class<?> moduleClass : moduleClasses) {
            Collection<MyCollectionUtils.FrequencyCheckEle> frequencyAbleCollection = new ArrayList<MyCollectionUtils.FrequencyCheckEle>();
            for (Method method : moduleClass.getDeclaredMethods()) {
                frequencyAbleCollection.add(new MyCollectionUtils.FrequencyCheckEle(method.getName(), method.toString()));
            }

            try {
                MyCollectionUtils.checkFrequency(frequencyAbleCollection, 2);
            } catch (Exception e) {
                throw new PrivilegeInitException("the method of controller can not be overloaded:", e);
            }
        }
    }

    private static class PrivilegeInitException extends RuntimeException {
        public PrivilegeInitException(String message) {
            super(message);
        }

        public PrivilegeInitException(String message, Throwable cause) {
            super(message, cause);
        }
    }

    private void validateAllClassModuleCode(Set<Class<?>> moduleClasses) {

        Collection<MyCollectionUtils.FrequencyCheckEle> frequencyAbleCollection = new ArrayList<MyCollectionUtils.FrequencyCheckEle>();
        for (Class<?> moduleClass : moduleClasses) {
            if (moduleClass.isAnnotationPresent(Module.class)) {
                Module module = moduleClass.getAnnotation(Module.class);
                frequencyAbleCollection.add(new MyCollectionUtils.FrequencyCheckEle(module.code(), "moduleCode=" + module.code() + " " + moduleClass.toString()));

            }
        }
        MyCollectionUtils.checkFrequency(frequencyAbleCollection);
    }

    public static void main (String[] args) {
        System.out.println(MD5.MD5Encode("admin"));
    }

    public static Enumeration createDemoEnumeration(){
        Vector v=new Vector();
        v.add("Tom");
        v.add("Bell");
        v.add("Neo");
        return v.elements();
    }

    private SysRole configAdminRole(Set<SysPrivilege> privilegesPersistenced) {
        //配置admin角色
        //如果admin角色不存在，就添加
        Conds roleConds = new Conds();
        roleConds.addFilter("code", "admin");
        List<SysRole> roleList = this.list(SysRole.class, roleConds);
        SysRole sysRole = null;
        if(roleList == null || roleList.isEmpty()) {
            sysRole = new SysRole();
            sysRole.setName("管理员");
            sysRole.setCode("admin");
            resetPrivilegesOfAdminRole(privilegesPersistenced, sysRole);
            this.save(sysRole);
        } else {
            sysRole = roleList.get(0);
            resetPrivilegesOfAdminRole(privilegesPersistenced, sysRole);
            this.merge(SysRole.class, sysRole);
        }

        return sysRole;
    }

    private void resetPrivilegesOfAdminRole(Set<SysPrivilege> privilegesPersistenced, SysRole sysRole) {
        XsvMaker xsvMaker = new XsvMakerImpl();
        xsvMaker.collectionToXsv(SysPrivilege.class, privilegesPersistenced, new CollectionValueGetter<SysPrivilege>() {
            @Override
            public String getValue(SysPrivilege object) {
                return object.getCode();
            }
        });
        sysRole.setPrivileges(xsvMaker.getResult());
    }

    private Set<SysPrivilege> getAllPrivilegesPersistenced() {
        Set<SysPrivilege> retVal = new HashSet<SysPrivilege>();
        retVal.addAll(this.list(SysPrivilege.class));
        return retVal;
    }

    private Set<SysPrivilege> getAllPrivilegesInProject(Set<Class<?>> moduleClasses) {
        Set<SysPrivilege> allPrivilegesInProject = new HashSet<SysPrivilege>();
        for (Class<?> moduleClass : moduleClasses) {
            if (moduleClass.getSuperclass() != SpringMVCBaseController.class) {
                throw new RuntimeException("需要权限控制的类必须是一个继承SpringMVCBaseController的类");
            }

            SysPrivilege modulePrivilege = getModulePrivilege(moduleClass);

            allPrivilegesInProject.add(modulePrivilege);


            String actionUrlPrefix = moduleClass.getAnnotation(RequestMapping.class).value()[0];
            Method[] declaredMethods = moduleClass.getDeclaredMethods();
            for (Method methodOfModule : declaredMethods) {
                if (methodOfModule.isAnnotationPresent(ModuleFunction.class)) {

                    SysPrivilege moduleFunctionPrivilege = getModuleFunctionPrivilege(moduleClass, modulePrivilege, actionUrlPrefix, methodOfModule);
                    allPrivilegesInProject.add(moduleFunctionPrivilege);
                }
            }
        }

        return allPrivilegesInProject;
    }

    private SysPrivilege getModuleFunctionPrivilege(Class<?> moduleClass, SysPrivilege modulePrivilege, String actionUrlPrefix, Method methodOfModule) {
        ModuleFunction moduleFunctionAnnotation = methodOfModule.getAnnotation(ModuleFunction.class);
        RequestMapping requestMapping = methodOfModule.getAnnotation(RequestMapping.class);

        Method[] allMethodOfModule = moduleClass.getDeclaredMethods();

        SysPrivilege moduleFunctionPrivilege = new SysPrivilege();
        moduleFunctionPrivilege.setName(moduleFunctionAnnotation.value());
        moduleFunctionPrivilege.setSysPrivilege(modulePrivilege);
        moduleFunctionPrivilege.setCode(getPrivilegeCode(moduleClass, methodOfModule));
        moduleFunctionPrivilege.setUrl(getUrl(actionUrlPrefix, requestMapping.value()[0]));

        if (moduleFunctionAnnotation.moduleFunctionType() == ModuleFunctionType.NORMAL) {
            moduleFunctionPrivilege.setType(PrivilegeType.NORMAL);

            //功能权限可以拥有其对应的菜单权限，下面对其进行配置。
            String menuPrivilegeMethodName = moduleFunctionAnnotation.menuPrivilegeMethodName();
            if (MyStringUtils.hasText(menuPrivilegeMethodName)) {
                for (Method method : allMethodOfModule) {
                    if (method.getName().equals(menuPrivilegeMethodName)) {
                        //ModuleFunction.menuPrivilegeMethodName指定的方法名称上面必须有MouduleFunction注解，且必须是MENU类型
                        validateMenuModuleFunction(method);
                        SysPrivilege menuPrivilege = this.getModuleFunctionPrivilege(moduleClass, modulePrivilege, actionUrlPrefix, method);
                        moduleFunctionPrivilege.setMenuPrivilege(menuPrivilege);
                        break;
                    }
                }
            }

        } else if (moduleFunctionAnnotation.moduleFunctionType() == ModuleFunctionType.MENU) {
            moduleFunctionPrivilege.setType(PrivilegeType.MENU);
            moduleFunctionPrivilege.setShowStatus(moduleFunctionAnnotation.showStatus());
        }
        return moduleFunctionPrivilege;
    }

    private void validateMenuModuleFunction(Method method) {
        boolean checkPass = false;
        if (method.isAnnotationPresent(ModuleFunction.class)) {
            ModuleFunction annotation = method.getAnnotation(ModuleFunction.class);
            if (annotation.moduleFunctionType() == ModuleFunctionType.MENU) {
                checkPass = true;
            }
        }

        if (!checkPass) {
            throw new PrivilegeInitException("ModuleFunction.menuPrivilegeMethodName指定的方法名称上面必须有MouduleFunction注解，且必须是MENU类型");
        }
    }

    private SysPrivilege getModulePrivilege(Class<?> moduleClass) {
        Module moduleAnnotation = moduleClass.getAnnotation(Module.class);
        //每一个被@Module注释的类代表一个权限分组
        SysPrivilege modulePrivilege = new SysPrivilege();
        modulePrivilege.setName(moduleAnnotation.name());
        modulePrivilege.setType(PrivilegeType.PRIVILEGE_GROUP);
        modulePrivilege.setCode(moduleAnnotation.code());
        return modulePrivilege;
    }


    private String getUrl(String actionUrlPrefix, String methodUrl) {
        if (!methodUrl.endsWith(".do")) {
            methodUrl = methodUrl + ".do";
        }
        return actionUrlPrefix + methodUrl;
    }

    private String getPrivilegeCode(Class<?> moduleClass, Method methodOfModule) {
        Module moduleAnnotation = moduleClass.getAnnotation(Module.class);
        return (moduleAnnotation.code() + "-" + methodOfModule.getName()).replaceAll("\\.", "_");
    }

}